import java.io.FileReader;
import java.io.FileWriter;
import java.io.Closeable;
import java.io.IOException;

/**
 * This is the 'Main' class of all Lab 2 operations. It reads in the arguments
 * to ensure that 4 valid file names have been provided, and then sends all of
 * the tasks to other classes. The 'Decoder' is the loader of the input file
 * data into memory. This data holds all of the values, as well as instructions
 * for the machine to execute. Once the data has been properly read into the
 * Machine architecture, with all error handling being taken care of at that
 * level, the machine passes each instruction to the proper location. Once
 * there, the instruction classes handle the operations, as well as further
 * checking for errors in the input.
 * 
 * @author Seth Mielke, Jonathan Hsu
 * 
 * @modified 8/6/11
 */
public class Lab2 {
	// Declare handles for each file read from and writen to.
	private static FileReader execin;
	private static FileReader pin;
	private static FileWriter pout;
	private static FileWriter ptrace;

	public static void main(String[] args) {
		/*
		 * Special case for opening the report file is needed, because this is
		 * where the subsequent exceptions/errors will be logged. Also, if
		 * args[3] exists, all 4 parameters have been passed.
		 */
		try {
			ptrace = new FileWriter(args[3]);
		} catch (ArrayIndexOutOfBoundsException e) {
			logError("Too few arguments. Four arguments required.");
			return;
		} catch (IOException e) {
			logError("Unable to to open trace file: " + args[3]);
			return;
		}

		try {
			// Open streams for three remaining files. Buffered is faster.
			execin = new FileReader(args[0]);
			pin = new FileReader(args[1]);
			pout = new FileWriter(args[2]);

			Decoder decoder = new Decoder();
			Word[] memory = decoder.instructionsToParse(execin, pout);
			int pcounter = decoder.returnPC();

			Machine machine = new Machine(memory, pcounter, pin, pout, ptrace);
			machine.run();
		} catch (IOException e) {
			logError("A file handling error occured. Make sure that permissions "
					+ "are set correctly and that the primary and auxiliary "
					+ "input files exists at their specified locations.");
		} finally {
			closeQuietly(ptrace);
			closeQuietly(execin);
			closeQuietly(pin);
			closeQuietly(pout);
		}
	}

	public static void closeQuietly(Closeable s) {
		if (null == s) {
			return;
		}
		try {
			s.close();
		} catch (IOException e) {
			// ignore
		}
	}

	private static void logError(String message) {
		String error_message = "ERROR: " + message;
		System.err.println(error_message);
        if (pout != null) {
            try {
                pout.write(error_message);
                pout.write(System.getProperty("line.separator"));
            } catch (IOException e) {
                // ingore
            }
        }
	}
}
